/*
 * Copyright (C) 2012 Tomas Shestakov. <http://code.google.com/p/jmmo/>
 */

package jmmo.engine.event

/**
 * Event which has some type. The parent of all typed events.
 * Instances of this class should be created only in rare cases.
 * The event type provides additional classification to events of the same Event class.
 * By subscribing to the parent type of event you will receive events of child types.
 * <p></p>
 * Событие имеющее некий тип. Родитель всех типизированных событий.
 * Экземпляры этого класса должны создаваться лишь в редких случаях.
 * Тип события обеспечивает дополнительную классификацию событий одного класса событий.
 * Подписавшись на родительский тип события будешь получать события дочерних типов.
 * @param source source of the event
 * @param eventType type of the Event
 * @author Tomas Shestakov
 */
class TypedEvent(source: AnyRef, val eventType: EventType[_ <: TypedEvent]) extends Event(source) {
  jmmo.util.requireNonNull(eventType, "eventType of TypedEvent cannot be null")

  /**
   * Creates instance of the TypedEvent with specified source and `TypedEvent.All` as type
   * @param source source of the event
   */
  def this(source: AnyRef) = this(source, TypedEvent.All)
}

object TypedEvent {
  /**
   * The parent type of all types of events (equals `EventType.Root`).
   */
  val All = EventType.Root
  /**
   * Creates instance of the TypedEvent with specified source and type
   * @param source source of the event
   * @param eventType type of the Event
   * @return new instance of the TypedEvent class
   */
  def apply(source: AnyRef, eventType: EventType[_ <: TypedEvent]) = new TypedEvent(source, eventType)
  /**
   * Creates instance of the TypedEvent with specified source and `TypedEvent.All` as type
   * @param source source of the event
   * @return new instance of the TypedEvent class
   */
  def apply(source: AnyRef) = new TypedEvent(source)

  def unapply(event: TypedEvent): Option[(AnyRef, EventType[_ <: TypedEvent])] =
    if (event eq null) None else Some(event.source, event.eventType)
}